package com.amigo.online.provider.user.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import javax.annotation.Resource;

import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.amigo.online.common.base.service.BaseService;
import com.amigo.online.common.core.response.Response;
import com.amigo.online.common.core.response.StatusCode;
import com.amigo.online.common.param.RedisKey;
import com.amigo.online.common.param.dto.adv.AdvTantanDto;
import com.amigo.online.common.param.dto.user.ProbePeopleDto;
import com.amigo.online.common.param.result.LikeOneInfo;
import com.amigo.online.common.param.result.PhotoInfo;
import com.amigo.online.common.param.result.ProbePersonAdvInfo;
import com.amigo.online.common.param.result.ProbePersonInfo;
import com.amigo.online.common.param.result.ProbePersonListInfo;
import com.amigo.online.common.param.result.UserInfo;
import com.amigo.online.provider.user.common.ConstantValue;
import com.amigo.online.provider.user.common.GlobalController;
import com.amigo.online.provider.user.common.RwRedisService;
import com.amigo.online.provider.user.exception.UserException;
import com.amigo.online.provider.user.mapper.UserDislikeMapper;
import com.amigo.online.provider.user.mapper.UserHobbyMapper;
import com.amigo.online.provider.user.mapper.UserLikeMapper;
import com.amigo.online.provider.user.mapper.UserMapper;
import com.amigo.online.provider.user.mapper.UserPhotosMapper;
import com.amigo.online.provider.user.model.entity.User;
import com.amigo.online.provider.user.model.entity.UserDislike;
import com.amigo.online.provider.user.model.entity.UserLike;
import com.amigo.online.provider.user.model.entity.UserPhotos;
import com.amigo.online.provider.user.mongo.dao.UserDao;
import com.amigo.online.provider.user.mongo.entity.UserEntity;
import com.amigo.online.provider.user.service.AdvFeignService;
import com.amigo.online.provider.user.service.UserLikeService;
import com.amigo.online.provider.user.util.BasicResponseHandle;
import com.amigo.online.provider.user.util.ConvertUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.client.MongoCursor;


@Service
@Transactional(rollbackFor = Exception.class)
public class UserLikeServiceImpl extends BaseService<UserLike> implements UserLikeService {

    @Resource
    private UserPhotosMapper userPhotosMapper;

    @Resource
    private UserHobbyMapper userhobbyMapper;

    @Autowired
    private UserDao userDao;

    @Autowired
    private UserLikeMapper userLikeMapper;

    @Autowired
    private UserDislikeMapper userDislikeMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    RwRedisService rwRedisService;

    private static String user_key = RedisKey.USER_REDIS_KEY;

    private static String USER_LIKE = RedisKey.USER_TAN_LIKEKEY;

    private static String USER_DISLIKE = RedisKey.USER_TAN_DISLIKEKEY;

    private static String block_key = RedisKey.USER_BLACK_REDIS_KEY;

    @Autowired
    AdvFeignService advFeignService;

    @Override
    public LikeOneInfo likeOne(Long userId) {
        Long nowTime = System.currentTimeMillis() / 1000;
        UserInfo nowUser = GlobalController.getNowUser();
        User user = new User();
        user.setId(userId);
        user = userMapper.selectByPrimaryKey(user);
        if (user == null) {
            throw new UserException(StatusCode.USER_EXCEPTION);
        }
        Long id = nowUser.getId();
        //判断今天0点到当前时间   喜欢的个数有没有超过500个
        Long zeroTime = GlobalController.getNowDay0Time();
        if (userLikeMapper.daySelectCount(id, zeroTime, nowTime) > 500) {
            throw new UserException(StatusCode.BEYOND_LIKE);
        }
        ;
        UserLike ul = new UserLike(id, userId, 0, null);
        ul.setCreatedTime(nowTime);
        ul.setRemark(0);
        //判断之前是否喜欢过
        if (userLikeMapper.countIsLike(id, userId) == 0) {
            userLikeMapper.insert(ul);
        }
        //插入队列
        rwRedisService.opsForList().leftPush(USER_LIKE + id, userId);
        Long size = rwRedisService.opsForListRead().size(USER_LIKE + id);
        if (size != null && size >= ConstantValue.MAX_LIKE_QUEUE) {
            //移除最后一位
            rwRedisService.opsForList().rightPop(USER_LIKE + id);
        }
        //判断是否是相互喜欢
        Boolean islike = false;
        if (userLikeMapper.countIsLike(userId, id) > 0) {
            islike = true;
            userLikeMapper.updateRelation(userId, id);
        }
        ;
        LikeOneInfo info = new LikeOneInfo(userId, user.getAvatar(), user.getNickname(), islike);
        logger.info(nowUser.getId() + "----喜欢了------" + userId);
        return info;
    }


    @Override
    public boolean dislikeOne(Long userId) {
        Long nowTime = System.currentTimeMillis() / 1000;
        UserInfo nowUser = GlobalController.getNowUser();
        User user = new User();
        user.setId(userId);
        user = userMapper.selectByPrimaryKey(user);
        if (user == null) {
            throw new UserException(StatusCode.USER_EXCEPTION);
        }
        Long id = nowUser.getId();
        UserDislike ul = new UserDislike();
        ul.setUserId(id);
        ul.setUserDislikeId(userId);
        ul.setCreatedTime(nowTime);
        ul.setDeleted(0);
        if (userDislikeMapper.insert(ul) != 1) {
            throw new UserException(StatusCode.INTERNAL_SERVER_ERROR);
        }
        //插入队列
        rwRedisService.opsForList().leftPush(USER_DISLIKE + id, userId);
        Long size = rwRedisService.opsForListRead().size(USER_DISLIKE + id);
        if (size != null && size >= ConstantValue.MAX_DISLIKE_QUEUE) {
            //移除最后一位
            rwRedisService.opsForList().rightPop(USER_LIKE + id);
        }
        logger.info(nowUser.getId() + "----不喜欢------" + userId);
        return true;
    }

    /**
     * 快速匹配
     */
    @Override
    public ProbePersonListInfo probePeople(ProbePeopleDto probePeopleDto, AdvTantanDto advTantanDto) {
        try {
            if (Double.valueOf(probePeopleDto.getLat()) == 0 && Double.valueOf(probePeopleDto.getLng()) == 0) {
                //都等于0，先去看看之前的经纬度 如果还是0  则更新成30334用户的经纬度
                Double[] coordinates = userDao.getUserById(30334L).getLoc().getCoordinates();
                probePeopleDto.setLat(String.valueOf(coordinates[0])); //维度
                probePeopleDto.setLng(String.valueOf(coordinates[1])); //经度
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //检查用户登录状态
        UserInfo u = GlobalController.getNowUser();
        //检测用户第一张头像的状态   三种  1没传    2审核未通过   3审核中的图片
        //3先放行   可以划别人    别人看不到他
        UserEntity user = userDao.getUserById(u.getId());
        if (user == null) {
            throw new UserException(StatusCode.USER_EXCEPTION);
        }
        //不走redis   因为要实时检测第一张照片的状态是否审核       查到后更新redis
        List<PhotoInfo> listp = getUserPhotoById(u.getId());
        UserInfo userInfo = (UserInfo) rwRedisService.hget(user_key, u.getId());
        if (null != userInfo) {
            userInfo.setPhotos(listp);
            rwRedisService.opsForHash().put(user_key, userInfo.getId(), userInfo);
        }
        ProbePersonListInfo result = new ProbePersonListInfo();
        result.setChecked(user.getChecked());
        result.setPhotoList(listp);
        List<ProbePersonInfo> resultList = new ArrayList<ProbePersonInfo>();

//        //获取喜欢自己，又不是自己不喜欢的人的id
//        List<Long> likeMe = userLikeMapper.selectLikeMe(u.getId());

        List<Long> resultIdList = getProbePeople(probePeopleDto, resultList, u.getId());
        //判断得到的id够不够10个   不够直接干掉缓存中的喜欢和不喜欢队列
        if (resultIdList.size() < 10) {
            rwRedisService.delete(USER_LIKE + u.getId());
            rwRedisService.delete(USER_DISLIKE + u.getId());
        }
        //查询用户照片  放进返回的对应列表里
        if (resultIdList.size() > 0) {
            List<UserPhotos> list = userPhotosMapper.selectPhotoByIdList(resultIdList);
            for (ProbePersonInfo ppi : resultList) {
                List<PhotoInfo> photos = new ArrayList<>();
                for (UserPhotos userPhotos : list) {
                    if (ppi.getId() == userPhotos.getUserId()) {
                        PhotoInfo pi = new PhotoInfo();
                        pi.setPhoto(userPhotos.getPhoto());
                        pi.setFirstImg(userPhotos.getFirstImg());
                        pi.setCheck(userPhotos.getChecked());
                        pi.setSort(userPhotos.getSort());
                        photos.add(pi);
                    }
                }
                //去重
                photos = removeDuplicate(photos);
                ppi.setPhotos(photos);
            }
        }

        advTantanDto.setAge(((System.currentTimeMillis() / 1000 - u.getBirthday()) / ConstantValue.YEAR_MILLIS));
        advTantanDto.setNumber(2);
        advTantanDto.setSex(u.getSex());
        findAroundPeopleAdv(advTantanDto, resultList);
        result.setProbePersonList(resultList);
        return result;
    }

    public   static   List<PhotoInfo>  removeDuplicate(List<PhotoInfo> list)  {
        for  ( int  i  =   0 ; i  <  list.size()  -   1 ; i ++ )  {
            for  ( int  j  =  list.size()  -   1 ; j  >  i; j -- )  {
                if  (list.get(j).getPhoto().equals(list.get(i).getPhoto()))  {
                    list.remove(j);
                }
            }
        }
        return list;
    }

    private void findAroundPeopleAdv(AdvTantanDto advTantanDto, List<ProbePersonInfo> resultList) {
        ResponseEntity<Response> res = advFeignService.getTantanVideoInfo(advTantanDto);
        if (BasicResponseHandle.convertListObject(res)) {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            List<ProbePersonAdvInfo> advlist = objectMapper.convertValue(res.getBody().getData(),
                    new TypeReference<List<ProbePersonAdvInfo>>() {
                    });
            int advSize = advlist.size();
            if (advSize > 0) {
                int size = resultList.size();
                int addNumber = size + advSize - ConstantValue.RANDOM_SHOW_TANTAN;
                if (addNumber > 0) {
                    for (; addNumber > 0; addNumber--) {
                        size--;
                        resultList.remove((int) Math.round(Math.random() * size));
                    }
                    if (advSize == 2) {
                        resultList.add((int) Math.round(Math.random() * size), advlist.get(0));
                        resultList.add((int) Math.round(Math.random() * size), advlist.get(1));
                    } else if (advSize == 1) {
                        resultList.add((int) Math.round(Math.random() * size), advlist.get(0));
                    }
                }
            }
        }
    }

    /**
     * 获取探探用户
     *
     *
     * @param probePeopleDto
     * @param resultList
     * @param userId
     * @return
     */
    @SuppressWarnings("unchecked")
    private List<Long> getProbePeople(ProbePeopleDto probePeopleDto, List<ProbePersonInfo> resultList, Long userId) {
        List<Long> resultIdList = new ArrayList<Long>();
        List<Long> resultLikeMe = new ArrayList<Long>();
        //重写方法
        //改为从缓存取出    拉黑/被拉黑   和   喜欢/不喜欢的人    和  已经匹配的用户  和  自身id 去重合成过滤idlist
        //带到查询方法里   随机出10个
        Set<Long> idList = new TreeSet<Long>();
        idList.add(userId);  //自身
        if (rwRedisService.hhasKey(block_key, userId)) {
            HashMap<String, TreeSet<Long>> map = (HashMap<String, TreeSet<Long>>) rwRedisService.hget(block_key, userId);
            if (map != null && map.size() > 0) {
                TreeSet<Long> blackSet = (TreeSet<Long>) map.get("blackId");
                TreeSet<Long> blackedSet = (TreeSet<Long>) map.get("blackedId");
                if (blackSet != null && blackSet.size() > 0) {
                    idList.addAll(blackSet);//拉黑
                }
                if (blackedSet != null && blackedSet.size() > 0) {
                    idList.addAll(blackedSet);//被拉黑
                }
            }
        }
        List<Object> likeIds = rwRedisService.opsForListRead().range(USER_LIKE + userId, 0, -1);
        List<Object> dislikeIds = rwRedisService.opsForListRead().range(USER_DISLIKE + userId, 0, -1);
        if (likeIds != null && likeIds.size() > 0) {
            idList = ListIntegerToLong(likeIds, idList);//喜欢
        }
        if (dislikeIds != null && dislikeIds.size() > 0) {
            idList = ListIntegerToLong(dislikeIds, idList);//不喜欢
        }
        List<Long> list = userLikeMapper.selectProbePersonId(userId);
        if (list != null && list.size() > 0) {
            idList.addAll(list);//已经匹配的用户
        }

        List<Long> likeMe = userLikeMapper.selectLikeMe(GlobalController.getNowUser().getId());
//        for(Long id:idList){
//            for (int i = likeMe.size()-1; i > 0; i--) {
//                if(id.equals(likeMe.get(i))){
//                    likeMe.remove(i);
//                }
//            }
//        }

        for (int i = likeMe.size()-1; i >= 0; i--) {
            for (Long id:idList) {
                if(id.equals(likeMe.get(i))){
                    likeMe.remove(i);
                    break;
                }
            }
        }


        int size = 0;
        //喜欢我的人
        MongoCursor<Document> cursorLikeMe = userDao.probePeopleLikeMe(probePeopleDto, userId, idList, likeMe);
        while (cursorLikeMe.hasNext()) {
            if(size<10) {
                Document doc = cursorLikeMe.next();
                size++;
                ProbePersonInfo tempObj = new ProbePersonInfo();
                tempObj.setId(doc.getLong("_id"));
                tempObj.setNickname(doc.getString("nickname"));
                tempObj.setSex(doc.getString("sex"));
                tempObj.setAge(doc.getDouble("bir"));
                tempObj.setDistance(doc.getDouble("dis"));
                tempObj.setImg(doc.getString("firstImg"));
                tempObj.setSign(doc.getString("sign"));
                tempObj.setLoginTime(doc.getLong("loginTime"));
                tempObj.setJob(doc.getString("job"));
                tempObj.setBirthday(doc.getLong("birthday"));
                resultList.add(tempObj);
                resultIdList.add(doc.getLong("_id"));
            }
        }
        MongoCursor<Document> cursor = userDao.probePeople(probePeopleDto, userId, idList, size);
        while (cursor.hasNext()) {
            Document doc = cursor.next();
            ProbePersonInfo tempObj = new ProbePersonInfo();
            tempObj.setId(doc.getLong("_id"));
            tempObj.setNickname(doc.getString("nickname"));
            tempObj.setSex(doc.getString("sex"));
            tempObj.setAge(doc.getDouble("bir"));
            tempObj.setDistance(doc.getDouble("dis"));
            tempObj.setImg(doc.getString("firstImg"));
            tempObj.setSign(doc.getString("sign"));
            tempObj.setLoginTime(doc.getLong("loginTime"));
            tempObj.setJob(doc.getString("job"));
            tempObj.setBirthday(doc.getLong("birthday"));
            resultList.add(tempObj);
            resultIdList.add(doc.getLong("_id"));
        }
        return resultIdList;
    }


    private List<PhotoInfo> getUserPhotoById(Long id) {
        List<UserPhotos> list = userPhotosMapper.getListByUid(id);
        List<PhotoInfo> plist = ConvertUtil.UserPhotosToPhotoInfo(list);
        return plist;
    }


    private Set<Long> ListIntegerToLong(List<Object> list, Set<Long> idList) {
        for (Object long1 : list) {
            if (long1 instanceof Integer) {
                Integer l1 = (Integer) long1;
                Long l2 = l1.longValue();
                idList.add(l2);
            } else if (long1 instanceof Long) {
                Long l1 = (Long) long1;
                idList.add(l1);
            }
        }
        return idList;
    }

//	@Override
//	public LikeOneInfo likeOne(Long userId) {
//		Long nowTime = System.currentTimeMillis()/1000;
//		UserInfo nowUser = GlobalController.getNowUser();
//		User user = new User();
//		user.setId(userId);
//		user = userMapper.selectByPrimaryKey(user);
//		if(user==null) {
//			throw new UserException(StatusCode.USER_EXCEPTION);
//		}
//		Long id = nowUser.getId();
//		UserLike ul = new UserLike(id, userId, 0, null);
//		ul.setCreatedTime(nowTime);
//		//判断今天0点到当前时间   喜欢的个数有没有超过500个
//		Long zeroTime = GlobalController.getNowDay0Time();
//		if(userLikeMapper.daySelectCount(id,zeroTime,nowTime)>500) {
//			throw new UserException(StatusCode.BEYOND_LIKE);
//		};
//		if(userLikeMapper.insert(ul)!=1) {
//			throw new UserException(StatusCode.INTERNAL_SERVER_ERROR);
//		}
//		if(hashOperations.hasKey(tanKey, id)) {
//			HashMap<String, ArrayDeque<Long>> userlike = (HashMap<String, ArrayDeque<Long>>) hashOperations.get(tanKey,id);
//			ArrayDeque<Long> userlikeIds = userlike.get(USER_LIKE);
//			if(userlikeIds!=null) {
//				if(userlikeIds.size()>=ConstantValue.MAX_LIKE_QUEUE) {
//					userlikeIds.pollLast();
//				}
//				userlikeIds.offerFirst(userId);
//			}
//			userlike.put(USER_LIKE, userlikeIds);
//			hashOperations.put(tanKey, id, userlike);
//		}else {
//			ArrayDeque<Long> likeset = new ArrayDeque<>(ConstantValue.MAX_LIKE_QUEUE);
//			ArrayDeque<Long> dislikeset = new ArrayDeque<>(ConstantValue.MAX_DISLIKE_QUEUE);
//			HashMap<String, ArrayDeque<Long>> userlike = new HashMap<>();
//			likeset.offerFirst(userId);
//			userlike.put(USER_LIKE,likeset);
//			userlike.put(USER_DISLIKE,dislikeset);
//			hashOperations.put(tanKey, id, userlike);
//		}
//		//判断是否是相互喜欢
//		Boolean islike = false;
//		if(hashOperations.hasKey(tanKey, userId)) {
//			HashMap<String, ArrayDeque<Long>> userlike = (HashMap<String, ArrayDeque<Long>>) hashOperations.get(tanKey,userId);
//			ArrayDeque<Long> userlikeIds = userlike.get(USER_LIKE);
//			if(userlikeIds.contains(id)) {
//				islike = true;
//			}
//		}
//		LikeOneInfo info = new LikeOneInfo(userId, user.getAvatar(), user.getNickname(), islike);
//		logger.info(nowUser.getId()+"----喜欢了------"+userId);
//		return info;
//	}

//	@Override
//	public boolean dislikeOne(Long userId) {
//		Long nowTime = System.currentTimeMillis()/1000;
//		UserInfo nowUser = GlobalController.getNowUser();
//		User user = new User();
//		user.setId(userId);
//		user = userMapper.selectByPrimaryKey(user);
//		if(user==null) {
//			throw new UserException(StatusCode.USER_EXCEPTION);
//		}
//		Long id = nowUser.getId();
//		UserDislike ul = new UserDislike();
//		ul.setUserId(id);
//		ul.setUserDislikeId(userId);
//		ul.setCreatedTime(nowTime);
//		ul.setDeleted(0);
//		if(userDislikeMapper.insert(ul)!=1) {
//			throw new UserException(StatusCode.INTERNAL_SERVER_ERROR);
//		}
//		if(hashOperations.hasKey(tanKey, id)) {
//			HashMap<String, ArrayDeque<Long>> userdislike = (HashMap<String, ArrayDeque<Long>>) hashOperations.get(tanKey,id);
//			ArrayDeque<Long> userdislikeIds = userdislike.get(USER_DISLIKE);
//			if(userdislikeIds!=null) {
//				if(userdislikeIds.size()>=ConstantValue.MAX_DISLIKE_QUEUE) {
//					userdislikeIds.pollLast();
//				}
//				userdislikeIds.offerFirst(userId);
//			}
//			userdislike.put(USER_DISLIKE, userdislikeIds);
//			hashOperations.put(tanKey, id, userdislike);
//		}else {
//			ArrayDeque<Long> likeset = new ArrayDeque<>(ConstantValue.MAX_LIKE_QUEUE);
//			ArrayDeque<Long> dislikeset = new ArrayDeque<>(ConstantValue.MAX_DISLIKE_QUEUE);
//			HashMap<String, ArrayDeque<Long>> userlike = new HashMap<>();
//			dislikeset.offerFirst(userId);
//			userlike.put(USER_LIKE,likeset);
//			userlike.put(USER_DISLIKE,dislikeset);
//			hashOperations.put(tanKey, id, userlike);
//		}
//		logger.info(nowUser.getId()+"----不喜欢------"+userId);
//		return true;
//	}


}
